Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: unsurprising module imports #18

Merged
merged 1 commit into from
Apr 22, 2014
Merged

RFC: unsurprising module imports #18

merged 1 commit into from
Apr 22, 2014

Conversation

o11c
Copy link
Contributor

@o11c o11c commented Mar 23, 2014

This is an update of my proposed resolution for old-style RFC rust-lang/rust#11745

@nikomatsakis
Copy link
Contributor

I think your wording is slightly...antagonistic, which doesn't help your case. (Some of us, at least, find the current system quite logical.) This discussion is not helped by the lack of a good understanding of the full details of our name resolution algorithm, but I fear there may be some interaction. This proposal is certainly missing some details.

For example, if I have "somerandomfile.rs" in my directory tree that is never used, is it going to be compiled? You point at Python for precedent, and in that case the answer is no: files are only processed once they are imported by someone. In that case, we'd be unable to construct a full module tree without processing imports (processing imports essentially becomes intertwined with constructing the module tree). I am not sure how this affects the (not generally well understood) name resolution algorithm, but it's something to work out.

In general, I am reluctant to accept any change to the module system that does not include a reasonably complete specification of how name resolution should work (and we most certainly need to write such a description for the current system as well!). There are numerous complexities to consider.

@o11c
Copy link
Contributor Author

o11c commented Mar 26, 2014

I think your wording is slightly...antagonistic, which doesn't help your case. (Some of us, at least, find the current system quite logical.)

If I'm somewhat antagonistic, it's because people keep insisting that there is absolutely nothing wrong, despite the fact that this is probably the 2nd most common thing newcomers get confused about (after lifetime errors).

The current system is logical to some subset of people who understand it. I proposed a system that, I believe, is logical to people even before they understand all the details.

This discussion is not helped by the lack of a good understanding of the full details of our name resolution algorithm, but I fear there may be some interaction. This proposal is certainly missing some details.

I'm not intimately familiar with the technical details of name resolution, but my understanding is that (before or after my proposal) an object is in scope if one of:

  • you refer to it by an absolute path
  • you have a mod or extern crate statement and refer to it using a relative path
  • you use a use statement and refer to it using its name only

And a method is in scope if its trait is used (which is sometimes annoying, but a separate issue).

For example, if I have "somerandomfile.rs" in my directory tree that is never used, is it going to be compiled?

No. Some of the alternatives might do this (perhaps under the "java-style" alternative, though Java doesn't go that far); but I actually count this as an argument against mod *; because there's no reasonable way to say "This .rs file is meaningful and this one is a meaningless backup" unless you start whitelisting or blacklisting filename characters.

You point at Python for precedent, and in that case the answer is no: files are only processed once they are imported by someone. In that case, we'd be unable to construct a full module tree without processing imports (processing imports essentially becomes intertwined with constructing the module tree). I am not sure how this affects the (not generally well understood) name resolution algorithm, but it's something to work out.

Given that mod statements are already allowed in places other than the root of the crate, I don't see what changes. Yes, the "only once" logic makes the implementation slightly more complicated, but that's not the important cost.

In general, I am reluctant to accept any change to the module system that does not include a reasonably complete specification of how name resolution should work (and we most certainly need to write such a description for the current system as well!). There are numerous complexities to consider.

Since Rust doesn't have ADL (thank Turing for traits!), I don't see what the complexities are. Other than whether an unqualified path is taken as absolute or relative by default (which would be an argument for requiring absolute paths to start with ::), I don't see any ambiguity in getting things from modules, and I don't see any ambiguity in getting methods from traits. What am I missing?

@pcwalton
Copy link
Contributor

pcwalton commented Apr 1, 2014

 No. Some of the alternatives might do this (perhaps under the "java-style" alternative, though Java doesn't go that far); but I actually count this as an argument against mod *; because there's no reasonable way to say "This .rs file is meaningful and this one is a meaningless backup" unless you start whitelisting or blacklisting filename characters.

This doesn't seem safe to me because a module that contains only trait implementations will then never be picked up.

What am I missing?

Traits/impls above and how you deal with multiple namespaces (types versus values), whether it's allowed to chain an import off another one (use foo::bar; use bar::baz; —what does this do?) and how that interacts with multiple namespaces, how you deal with mutual recursion (you cannot do it the same way Python does), and so forth. This problem is not easy.

@o11c
Copy link
Contributor Author

o11c commented Apr 1, 2014

This doesn't seem safe to me because a module that contains only trait implementations will then never be picked up.

You just use the mod statement for that, probably in the module that declares either the trait or struct involved in the impl (since one of those must be satisfied).

how you deal with multiple namespaces (types versus values)

I'm a fan of forbidding the same identifier from being used in multiple namespaces. IMO the only reason people even think about it is because of compatibility with things like sigaction.

Is there anyone to defend allowing it?

whether it's allowed to chain an import off another one (use foo::bar; use bar::baz; —what does this do?)

Assuming the relative import model, that would be the same as use foo::bar::baz - since, under my system, all names from outside the current module go through an import.

(with the absolute import model, use foo::bar followed by use self::bar::baz would be equivalent to use foo::bar::baz)

(by "equivalent" I ignore the fact that it's also making bar available)

how you deal with mutual recursion (you cannot do it the same way Python does)

Why not? Python just follows the "if module has already started being import it, return immediately" approach - and since Rust doesn't have to execute as it goes, it avoids the problem to beware of when writing python code. (I mentioned this and the other approach on line 87 "To avoid cycles during compilation,")

@pcwalton
Copy link
Contributor

pcwalton commented Apr 1, 2014

We have to have the same identifier in multiple namespaces. Consider newtype structs: the name of the constructor is the name of the type.

@o11c
Copy link
Contributor Author

o11c commented Apr 1, 2014

We have to have the same identifier in multiple namespaces. Consider newtype structs: the name of the constructor is the name of the type.

Sure, but in that case, it's the same "object" that can be used in more than one way.

As a single object, it can either be in scope or not in scope.

@pcwalton
Copy link
Contributor

pcwalton commented Apr 1, 2014

You just use the mod statement for that, probably in the module that declares either the trait or struct involved in the impl (since one of those must be satisfied).

I don't see much of a difference between that and the current system, except that it seems like that would make it inconsistent as to when mod is needed and it's not.

@o11c
Copy link
Contributor Author

o11c commented Apr 1, 2014

I don't see much of a difference between that and the current system, except that it seems like that would make it inconsistent as to when mod is needed and it's not.

It's quite simple. You use mod every time you want to import a module from the current directory. You use use every time you want to take a name (module or not) from some other module.

This is how everybody coming into Rust expects things to Just Work. Choosing exactly one place to put the mod statement (event if the answer is mod.rs or lib.rs) is far less intuitive.

@pcwalton
Copy link
Contributor

pcwalton commented Apr 1, 2014

But sometimes you want to specify that you want to bring this module into
the compilation unit without taking a name from it. I would personally be
pretty confused by this system.

On Tuesday, April 1, 2014, o11c notifications@github.com wrote:

I don't see much of a difference between that and the current system,
except that it seems like that would make it inconsistent as to when mod is
needed and it's not.

It's quite simple. You use mod every time you want to import a module
from the current directory. You use use every time you want to take a name
(module or not) from some other module.

This is how everybody coming into Rust expects things to Just Work.
Choosing exactly one place to put the mod statement (event if the answer is
mod.rs or lib.rs) is far less intuitive.


Reply to this email directly or view it on GitHub.<
https://ci3.googleusercontent.com/proxy/j08cex1umECMdNVPpFdIvi4DDjXUG1Y5aKNh_g7Akd4mBBUgEoIe5rz63BNR66RPhB_nvtzm-L2CiHdun4HXFYOz0T60Y9nAbz5GYe8PcLK1kCIQcl6TX_9pC0gD-p6gXp6tnuDlKaAUQP9Ushd8O7hA7R3aYrGyY-jOjtbz4nrR2y41fdRNl_zSNZibu7TdD8BKBRxx475jB2Weo9uKWpCUiV5tNnDj-UcOc-eN5522DjD4sp1W0WtLz6fpzT-i43Et5_jloFCjZCViPsaUI443YqAp=s0-d-e1-ft#https://github.com/notifications/beacon/157897__eyJzY29wZSI6Ik5ld3NpZXM6QmVhY29uIiwiZXhwaXJlcyI6MTcxMTk5MDIxOCwiZGF0YSI6eyJpZCI6MjgzMTM0NTJ9fQ==--ed0fe5818964781200643e9bb926087091bf5062.gif

@o11c
Copy link
Contributor Author

o11c commented Apr 1, 2014

But sometimes you want to specify that you want to bring this module into
the compilation unit without taking a name from it. I would personally be
pretty confused by this system.

For modules, the following cases exist:

  • mod foo; - add the name foo referring to the contents of the module from a file foo.rs (or foo/mod.rs) relative to the current directory.
  • use ::foo::bar - add the name bar referring to the contents of the file foo/bar.rs from the project root, provided that /foo/mod.rs exists and contains mod bar;.
  • use self::foo::baz - add the name baz referring to the contents of the file foo/baz.rs relative to the current directory, provided that foo/mod.rs exists and contains mod baz;.

For cases 2 and 3 there, it makes sense that foo/mod.rs contains the mod statement because it is intended as a semipublic module. (It would also be possible to have bar or baz refer to some other object, but this is the most likely case if foo/ba?.rs exists.)

@brson brson merged commit c00c8f5 into rust-lang:master Apr 22, 2014
@brson
Copy link
Contributor

brson commented Apr 22, 2014

Closing, not accepted. Assigned RFC 9 and moved to the 'rejected' folder. Reasoning is as stated during review. Thank you.

pcwalton added a commit that referenced this pull request Sep 11, 2014
@Centril Centril added A-modules Proposals relating to modules. A-resolve Proposals relating to name resolution. labels Nov 23, 2018
cramertj pushed a commit that referenced this pull request Mar 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-modules Proposals relating to modules. A-resolve Proposals relating to name resolution.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants